﻿using System;
using System.Collections.ObjectModel;
using System.Collections.Generic;

namespace System.Erp.UI
{
    /// <summary>
    /// 提供统一的框架，用来控制某个按钮、菜单或文本框最终是有效还是只读这样的属性。
    /// </summary>
    /// <remarks>
    /// <para>
    /// 在ERP某个浏览界面中，其“删除”按钮的有效性(Enabled)可能受很多因素的影响。例如是否
    /// 至少选择了一条记录，以及用户是否有权限删除。也许你觉得很简单，像这样写：
    /// </para>
    /// <code>
    /// mnuDelete.Enabled = MustSelectOne() and UserCanDelete();
    /// </code>
    /// <para>
    /// 但是，如果现在第三方程序希望增加新的判断依据：此记录不能是已激活的，这是必须修改现有的代码。
    /// 此项目致力于组合型的应用，因此，这里的Enabled的取值一样是需要支持组合。
    /// </para>
    /// <para>
    /// 此类作为样式的基础设施，提供一种树形的决策模型，任何一个节点（一个ValueSelecter实例）允许
    /// 主张（advocate）一个值，那么这棵树的最终值将是此值。当然，任何节点也可以弃权（abstention）。当所有节点
    /// 弃权时，最终值为默认值。
    /// </para>
    /// <para>
    /// 在上面的例子中，菜单的Enabled本身持有一个ValueSelecter，对其直接的赋值将修改其根节点的表决值，另外的
    /// 两个因素将作为子表决器，当需要第三方时，仅需要使用二次开发添加额外的表决器。
    /// </para>
    /// </remarks>
    [System.Diagnostics.DebuggerDisplay("Value={Value},VoteResult={VoteResult}")]
    public class ValueSelecter<T>
    {

        /// <summary>
        /// 创建 ValueSelecter 的新实例，其默认为弃权。
        /// </summary>
        public ValueSelecter()
        {
            _thisVoteResult = VoteResult.Abstention;
            _thisValue = DefaultValue;
            _cachedValue = DefaultValue;
            _cachedItemsResult = VoteResult.Abstention;
        }

        //本节点的表决意见
        private VoteResult _thisVoteResult;
        //本节点的值
        private T _thisValue;

        /// <summary>
        /// 此表决器其默认的值，即弃权时的值
        /// </summary>
        public virtual T DefaultValue {
            get { return default(T); }
        }

        //缓存的子对象的意见
        private VoteResult _cachedItemsResult;
        /// <summary>
        /// 返回当前节点及其子节点的表决意见。
        /// </summary>
        public VoteResult VoteResult
        {
            get
            {
                //如果本节点有主张，那么认为就是主张。
                if (_thisVoteResult == UI.VoteResult.Advocate)
                {
                    return UI.VoteResult.Advocate;
                }

                //否则返回子节点的意见。
                return _cachedItemsResult;
            }
        }

        //上次计算的缓存结果
        private T _cachedValue;
        /// <summary>
        /// 返回当前节点及其以下节点的最终表决值。
        /// </summary>
        public T Value
        {
            get
            {
                return _cachedValue;
            }
            set
            {
                //更新本地的表决意见
                EqualityComparer<T> ec = EqualityComparer<T>.Default;
                if (!ec.Equals(_thisValue, value))
                {
                    _thisValue = value;

                    //如果新的值是默认值，认为是弃权。
                    if (ec.Equals(value,this.DefaultValue))
                    {
                        _thisVoteResult = VoteResult.Abstention;
                    }
                    else
                    {
                        //否则认为是 主张
                        _thisVoteResult = VoteResult.Advocate;
                    }

                    Refresh();
                }
            }
        }

        private void Refresh()
        {
            T newValue = GetValue();
            EqualityComparer<T> ec = EqualityComparer<T>.Default;
            if (!ec.Equals(newValue,_cachedValue))
            {
                _cachedValue = newValue;
                this.OnValueChanged(EventArgs.Empty);
            }
        }

        /// <summary>
        /// 当Value的值发生改变后触发
        /// </summary>
        /// <param name="e">事件参数</param>
        protected virtual void OnValueChanged(EventArgs e)
        {
            if (this.ValueChanged != null)
            {
                this.ValueChanged(this, e);
            }
        }

        /// <summary>
        /// 当Value的值发生改变后触发此事件
        /// </summary>
        public event EventHandler ValueChanged;

        /// <summary>
        /// 重新计算结果
        /// </summary>
        private T GetValue()
        {
            //如果本地是主张，优先
            if (this._thisVoteResult == UI.VoteResult.Advocate)
            {
                return _thisValue;
            }

            //看子节点的意见
            if ((this._items != null) && (this._items.Count >0))
            {
                foreach (var item in _items)
                {
                    //此子节点实际还会看 他的子节点的意见
                    if (item.VoteResult == UI.VoteResult.Advocate)
                    {
                        _cachedItemsResult = UI.VoteResult.Advocate;
                        return item.Value;
                    }
                }
            }

            //当没有任何人主张时，使用默认值
            _cachedItemsResult = UI.VoteResult.Abstention;
            return this.DefaultValue;
        }

        /// <summary>
        /// 重置当前节点的表决结果为弃权。
        /// </summary>
        public void Reset()
        {
            this.Value = this.DefaultValue;
        }

        private ValueSelecterCollection _items;
        /// <summary>
        /// 返回所有子表决器对象。
        /// </summary>
        public Collection<ValueSelecter<T>> Items
        {
            get {
                if (_items == null)
                {
                    lock (this)
                    {
                        if (_items == null)
                        {
                            _items = new ValueSelecterCollection(this);
                        }
                    }
                }
                return _items;
            }
        }

        #region ValueSelecterCollection

        private sealed class ValueSelecterCollection : Collection<ValueSelecter<T>>
        {
            private ValueSelecter<T> _owner;
            private EventHandler _valueChangedHandler;

            public ValueSelecterCollection(ValueSelecter<T> owner)
            {
                this._owner = owner;
                _valueChangedHandler = this.OnValueChanged;
            }

            private void OnValueChanged(object sender, EventArgs e)
            {
                _owner.Refresh();
            }

            protected override void InsertItem(int index, ValueSelecter<T> item)
            {
                if (item == null)
                {
                    throw new ArgumentNullException("item");
                }

                base.InsertItem(index, item);
                item.ValueChanged += _valueChangedHandler;
                _owner.Refresh();
            }

            protected override void ClearItems()
            {
                foreach (var item in this)
                {
                    item.ValueChanged -= _valueChangedHandler;
                }
                base.ClearItems();
                _owner.Refresh();
            }

            protected override void RemoveItem(int index)
            {
                this[index].ValueChanged -= _valueChangedHandler;
                base.RemoveItem(index);
                _owner.Refresh();
            }

            protected override void SetItem(int index, ValueSelecter<T> item)
            {
                if (item == null)
                {
                    throw new ArgumentNullException("item");
                }

                this[index].ValueChanged -= _valueChangedHandler;
                base.SetItem(index, item);
                this[index].ValueChanged += _valueChangedHandler;

                _owner.Refresh();
            }
        }
        #endregion
    }
}
